/******************************************************************************

    Simple Authentication and Authorisation System (SAAS)

    saas.h

    Copyright (C) 2011  Josh Goes


    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    If you require a mailing address for this software, please send your
    mail to the following address:
        SAAS
        GPO Box 2973
        BRISBANE QLD 4001
        AUSTRALIA

******************************************************************************/


#ifndef __H_715a47ee3f2ed715149570cc0b201886_
#define __H_715a47ee3f2ed715149570cc0b201886_

#include <stdint.h>
#include <asm/byteorder.h>
#include <syslog.h>
#include <stdio.h>



///////////////////////////////////////////////////////////////////////////////////////////////
//
//  CONFIGURATION OPTIONS
//

#define SAAS_MAX_NUM_HOSTS          64
#define SAAS_MAX_DNS_HOST_LEN       256

#define SAAS_CONF_PATH_DEFAULT      "/etc/saas.conf"

// note: the username len cannot be changed, due to the way strings are encoded
// in the SAAS protocol.
#define SAAS_MAX_USERNAME_LEN		256
#define	SAAS_MAX_GROUPNAME_LEN		SAAS_MAX_USERNAME_LEN
#define SAAS_MAX_SECRET_LEN         512
#define SAAS_MAX_SALT_LEN			512

// /dev device that generates random or pseudo-random data
#define SAAS_RANDOM_FILE            "/dev/urandom"

#define SAAS_DEFAULT_PORT           1234

// max packet length
//   because IPv4 has a limit of 65535 bytes, we'll set that limit here.
#define SAAS_MAX_PKT_LEN            65535


#if defined (__LITTLE_ENDIAN_BITFIELD)
#define SAAS_ENDIAN_LITTLE
#elif defined (__BIG_ENDIAN_BITFIELD)
#define SAAS_ENDIAN_BIG
#else
#error "Could not figure out the endianness of the CPU. This is critical for compilation."
#endif


///////////////////////////////////////////////////////////////////////////////////////////////
//
//  CONSTANTS
//

// operation return codes
#define SAAS_OP_SUCCESS                                             0x0000

// operation-specific errors
#define SAAS_OP_INVALID_PASS                                        0x1000
#define SAAS_OP_USER_NOT_FOUND                                      0x1001
#define SAAS_OP_GROUP_NOT_FOUND                                     0x1002
#define SAAS_OP_USER_UNAUTHORISED									0x1003
#define SAAS_OP_USERNAME_TOO_LONG                                   0x1004

// general errors
#define SAAS_OP_SERVER_ERROR                                        0x2000
#define SAAS_OP_NO_HOSTS                                            0x2001
#define SAAS_OP_DECRYPT_ERROR                                       0x2002
#define SAAS_OP_MAGIC_ERROR                                         0x2003
#define SAAS_OP_FILE_ERROR                                          0x2004
#define SAAS_OP_PAD_ERROR                                           0x2005
#define SAAS_OP_PARSE_ERROR                                         0x2006
#define SAAS_OP_ARG_ERROR                                           0x2007
#define SAAS_OP_MEM_ERROR                                           0x2008
#define SAAS_OP_TIMEOUT_ERROR                                       0x2009
#define SAAS_OP_SOCKET_ERROR                                        0x200A
#define SAAS_OP_MALFORMED_REQUEST                                   0x200B
#define SAAS_OP_MALFORMED_RESPONSE                                  0x200C


// encryption types
#define SAAS_ENC_TYPE_AES256CBC_SHA256                              0x00000001
#define SAAS_ENC_TYPE_AES256ECB_SHA256                              0x00000002
#define SAAS_ENC_TYPE_AES128CBC_SHA256XOR                           0x00000003
#define SAAS_ENC_TYPE_AES128ECB_SHA256XOR                           0x00000004


// key encryption times
#define	SAAS_KEY_TIME_TYPE_SEC			0x00
#define	SAAS_KEY_TIME_TYPE_MIN			0x01


// group member types
#define SAAS_GROUP_MEMBER_TYPE_GROUP    0x00
#define SAAS_GROUP_MEMBER_TYPE_USER		0x01


// host types
#define SAAS_HOST_TYPE_DNS                                          0x01
#define SAAS_HOST_TYPE_IPV4                                         0x02
#define SAAS_HOST_TYPE_IPV6                                         0x03

#define	SAAS_HOST_FLAG_RESOLVED										0x01


// log destinations
#define SAAS_LOG_NONE        0
#define SAAS_LOG_STDOUT      1
#define SAAS_LOG_STDERR      2
#define SAAS_LOG_SYSLOG      3
#define SAAS_LOG_FILE        4
#define SAAS_LOG_PAM_SYSLOG  5



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  HOST  STRUCTURE
//
//  This structure is used by the saas_t type to keep a list of all hosts declared in the configuration file.
//
typedef struct st_saas_host
{
	// the timeout value for this host (in milliseconds).
	uint32_t  timeout;

	// the port number on which we connect to them
	uint16_t  port;

	// space for their IPv4 address, if it's an IPv4 host record
	uint8_t   ipv4_addr[4];

	// space for their IPv6 address, if it's an IPv6 host record
	uint8_t   ipv6_addr[16];

	// space for their DNS name, if it's a DNS-based host record
	uint8_t   dns_name[SAAS_MAX_DNS_HOST_LEN];

	// host declaration type  (see SAAS_HOST_TYPE_xyz and SAAS_HOST_FLAG_xyz defines above)
	uint8_t   flags;
	uint8_t   type;

} saas_host_t;


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  INSTANCE  STRUCTURE
//
//  This structure defines the instance of SAAS by a client. It contains both the configuration file declarations, as well as the
//  clients logging perferences, and other things.
//
typedef struct st_saas
{
	//
	// Logging Information
	//
	uint8_t        log_type;
	FILE          *log_file;
	uint8_t        log_level;
	void          *log_handle;



	//
	// Host Information
	//

	// the list of hosts to use
	uint8_t            num_hosts;
	saas_host_t        hosts[SAAS_MAX_NUM_HOSTS+1];
	uint16_t           host_idx_order[SAAS_MAX_NUM_HOSTS+1];
	uint16_t           pos_order_idx;

	// order in which hosts will get connected
	uint8_t  host_order;



	//
	// Encryption Information
	//

	// what kind of encryption and hash algorithms we'll be using to talk privately
	uint32_t  enc_type;

	// whether the encryption key changes every minute or second
	uint8_t  key_time_type;

	// specify how many +- minutes/seconds to try decrypting before giving up.
	uint16_t  key_time_tolerance;

	// password salt
	uint8_t  pw_salt[SAAS_MAX_SALT_LEN];
	uint16_t pw_salt_len;

	// the pre shared secret key, shared by all clients and servers in an installation.
	uint16_t  secret_len;
	uint8_t   secret[SAAS_MAX_SECRET_LEN];

	// number of seconds to adjust the system's "UTC" timezone to get real UTC time.
	int32_t   time_adjust;




	//
	// Networking Information
	//

	// prefer DNS lookups for AAAA records first before trying A records?
	uint8_t  dns_prefer_ipv6;
	uint8_t  dns_prefer_ipv4;

	// try all IPs in DNS records that have multiple IPs
	uint8_t  dns_try_all_ips;

	// whether to use ipv4/ipv6
	uint8_t  use_ipv4;
	uint8_t  use_ipv6;

	// timeout in ms for waiting from a reply from hosts...
	uint32_t  timeout;

} saas_t;






//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  USER  STRUCTURE
//
//  Made up of two structures, this identifies information about a user.  The user struct itself contains all the user
//  information, as well as a list of groups the user is a member of.
//
typedef struct st_saas_user_group
{
	uint32_t  gid;
	char     *groupname;
} saas_user_group_t;

typedef struct st_saas_user_info
{
	uint16_t  username_len;
	uint16_t  fullname_len;
	uint16_t  displayname_len;
	uint16_t  fname_len;
	uint16_t  lname_len;
	uint16_t  email_len;
	uint16_t  home_dir_len;
	uint16_t  shell_len;
	uint16_t  num_groups;
	uint16_t  _reserved0_len;
	uint16_t  _reserved1_len;
	uint16_t  _reserved2_len;
	uint16_t  _reserved3_len;
	uint16_t  _reserved4_len;
	uint16_t  _reserved5_len;
	uint16_t  _reserved6_len;

	// UID and GID of user.
	uint32_t  uid;
	uint32_t  gid;

	// pointers to strings.
	char *username;
	char *fullname;
	char *displayname;
	char *fname;
	char *lname;
	char *email;
	char *home_dir;
	char *shell;
	char *_reserved0;
	char *_reserved1;
	char *_reserved2;
	char *_reserved3;
	char *_reserved4;
	char *_reserved5;
	char *_reserved6;

	saas_user_group_t  **groups;

} saas_user_info_t;




//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  GROUP  STRUCTURE
//
//  Made up of two structures, this identifies information about a group.  The group struct itself contains all the group
//  information, as well as a list of members of the group, be they users or groups.
//
typedef struct st_saas_group_member
{
	// the type of group member (0 = group, 1 = user)
	uint8_t   type;

	// the GID or UID of the member
	uint32_t  id;

	// the groupname or username of the member.
	char     *name;
} saas_group_member_t;

typedef struct st_saas_group_info
{
	// the length of the groupname
	uint16_t  groupname_len;

	// total number of members in the group.
	uint16_t  num_members;

	// the GID of the group.
	uint32_t  gid;

	// the pointer to the group name string (with NULL terminator)
	char     *groupname;

	// the double pointer list of members.
	saas_group_member_t    **members;

} saas_group_info_t;



uint16_t saas_init( saas_t *inst , const char *conf_file , uint8_t log_level , uint8_t log_type , FILE *log_file , void *log_handle );
uint16_t saas_free( saas_t *inst );
void     saas_dump( saas_t *inst , const char *line_prefix );
char *saaserror( uint16_t  errcode );

// authentication request (with password expiry information being returned, as well as a yay/nay)
uint16_t saas_authenticate( saas_t *saas , const char *username , const char *password , uint32_t *pass_expire );

// UID <--> Username conversions
uint16_t saas_uid_to_username( saas_t *saas , uint32_t uid , char **username );
uint16_t saas_username_to_uid( saas_t *saas , const char *username , uint32_t *uid );

// GID <--> Groupname conversions
uint16_t saas_gid_to_groupname( saas_t *saas , uint32_t gid , char **groupname );
uint16_t saas_groupname_to_gid( saas_t *saas , const char *groupname , uint32_t *gid );

// retrieve ordinary information about a user
uint16_t saas_user_info_by_uid( saas_t *saas , uint32_t uid , saas_user_info_t **user_info );
uint16_t saas_user_info_by_username( saas_t *saas , const char *username , saas_user_info_t **user_info );

// retrieve information about a user plus a list of groups they're directly a member of.
uint16_t saas_user_info_with_groups_by_uid( saas_t *saas , uint32_t uid , saas_user_info_t **user_info );
uint16_t saas_user_info_with_groups_by_username( saas_t *saas , const char *username , saas_user_info_t **user_info );

// retrieve information about a user plus a flat list of all groups they're a member of, either directly or recursively.
uint16_t saas_user_info_with_all_groups_by_uid( saas_t *saas , uint32_t uid , saas_user_info_t **user_info );
uint16_t saas_user_info_with_all_groups_by_username( saas_t *saas , const char *username , saas_user_info_t **user_info );

// retrieve ordinary information about a group
uint16_t saas_group_info_by_gid( saas_t *saas , uint32_t gid , saas_group_info_t **group_info );
uint16_t saas_group_info_by_groupname( saas_t *saas , const char *groupname , saas_group_info_t **group_info );

// retrieve information about a group plus direct members of that group
uint16_t saas_group_info_with_members_by_gid( saas_t *saas , uint32_t gid , saas_group_info_t **group_info );
uint16_t saas_group_info_with_members_by_groupname( saas_t *saas , const char *groupname , saas_group_info_t **group_info );

// retrieve information about a group plus all members, direct or recursive, of that group
uint16_t saas_group_info_with_all_members_by_gid( saas_t *saas , uint32_t gid , saas_group_info_t **group_info );
uint16_t saas_group_info_with_all_members_by_groupname( saas_t *saas , const char *groupname , saas_group_info_t **group_info );




#endif // __H_715a47ee3f2ed715149570cc0b201886_

